﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Aragorn.SOA.ORM.DapperExtensions.Mapper;
using Aragorn.SOA.ORM.Lambda;
using Dapper;
using Aragorn.SOA.ORM.DapperExtensions.Mapper;
using Aragorn.SOA.ORM.Lambda;

namespace Aragorn.SOA.ORM
{
    public class UpdateSqlLamCommand<T> : SqlLamCommandBase
    where T : class
    {
        private SqlLam<T> query;

        private string tableName;

        private DbContextData Data
        {
            get;
            set;
        }

        private IDictionary<string, object> updateFields
        {
            get;
            set;
        }

        public UpdateSqlLamCommand(DbContextData contextData)
        {
            this.Data = contextData;
        }

        public UpdateSqlLamCommand<T> And(Expression<Func<T, bool>> expression)
        {
            this.query = this.query.And(expression);
            return this;
        }

        public int Execute()
        {
            if (this.query == null)
            {
                throw new Exception("修改数据，请设置过滤条件;如果没有条件，可以设置1==1");
            }
            List<string> list = new List<string>();
            IDictionary<string, object> queryParameters = this.query.QueryParameters;
            foreach (KeyValuePair<string, object> current in this.updateFields)
            {
                list.Add(current.Key + "=@" + current.Key);
                queryParameters.Add(current.Key, current.Value);
            }
            string sql = string.Format("update {0} set {1} WHERE {2}", this.tableName, string.Join(",", list), string.Join("", this.query.SqlBuilder.WhereConditions));
            return this.Data.Connection.Execute(sql, this.Data, queryParameters, this.Data.Transaction, this.Data.CommandTimeout, null);
        }

        internal override SqlLamBase GetBaseQuery()
        {
            return this.query;
        }

        public UpdateSqlLamCommand<T> Or(Expression<Func<T, bool>> expression)
        {
            this.query = this.query.Or(expression);
            return this;
        }

        public UpdateSqlLamCommand<T> Set(dynamic entity)
        {
            if (entity == (dynamic)null)
            {
                throw new Exception("the parameters cannot be empty");
            }
            object obj = entity;
            List<PropertyInfo> list = obj.GetType().GetProperties().ToList<PropertyInfo>();
            if (list.Count() == 0)
            {
                throw new Exception("the parameters cannot be empty");
            }
            AutoClassMapper<T> autoClassMapper = new AutoClassMapper<T>();
            List<PropertyInfo> propertyInfos = (
                from p  in list
                where !autoClassMapper.Properties.Any<IPropertyMap>((IPropertyMap c) => c.Name.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase))
                select p).ToList<PropertyInfo>();

            if (propertyInfos != null && propertyInfos.Count() > 0)
            {
                string[] tableName = new string[] { "参数对象中属性[", null, null, null, null };
                tableName[1] = string.Join(",",
                    from p in propertyInfos
                    select p.Name);
                tableName[2] = "]不属于表[";
                tableName[3] = autoClassMapper.TableName;
                tableName[4] = "]中的字段";
                throw new Exception(string.Concat(tableName));
            }
            IDictionary<string, object> strs = new Dictionary<string, object>();
            foreach (PropertyInfo propertyInfo in list)
            {
                strs.Add(propertyInfo.Name, propertyInfo.GetValue(obj));
            }
            this.tableName = autoClassMapper.TableName;
            this.updateFields = strs;
            return this;
        }

        public UpdateSqlLamCommand<T> Where(Expression<Func<T, bool>> expression)
        {
            this.query = (new SqlLam<T>()).Where(expression);
            return this;
        }

        public UpdateSqlLamCommand<T> WhereIsIn(Expression<Func<T, object>> expression, SqlLamCommandBase sqlQuery)
        {
            this.query = (new SqlLam<T>()).WhereIsIn(expression, sqlQuery.GetBaseQuery());
            return this;
        }

        public UpdateSqlLamCommand<T> WhereIsIn(Expression<Func<T, object>> expression, IEnumerable<object> values)
        {
            this.query = (new SqlLam<T>()).WhereIsIn(expression, values);
            return this;
        }

        public UpdateSqlLamCommand<T> WhereNotIn(Expression<Func<T, object>> expression, SqlLamCommandBase sqlQuery)
        {
            this.query = (new SqlLam<T>()).WhereNotIn(expression, sqlQuery.GetBaseQuery());
            return this;
        }

        public UpdateSqlLamCommand<T> WhereNotIn(Expression<Func<T, object>> expression, IEnumerable<object> values)
        {
            this.query = (new SqlLam<T>()).WhereNotIn(expression, values);
            return this;
        }
    }
}